package com.jrx.anytxn.reporting.handler;

import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.*;
import com.jrx.anytxn.common.uitl.StringUtils;
import com.jrx.anytxn.i18n.response.TxnRespResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 全局异常处理器
 */
@ControllerAdvice
public class GlobalExceptionHandler {
	private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	private Pattern pattern = Pattern.compile("\\[[\"']?(.+?)[\"']?]");

	private final static String EXCEPTION_HANDLER = "ExceptionHandler:";

	/**
	 * 对不能单独处理的异常进行统一处理
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = Exception.class)
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnExceptionHandler(Exception e) {
		logger.error(EXCEPTION_HANDLER,e);
		return new TxnRespResult<>().getFail(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getMsg());
	}

	/**
	 * 对运行时异常进行统一处理
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = TxnRuntimeException.class)
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnRuntimeExceptionHandler(TxnRuntimeException e) {
		logger.error(EXCEPTION_HANDLER,e);
		return new TxnRespResult<>().getFail(TxnRespCode.ERROR.getCode(), e.getErrMsg());
	}
	/**
	 * 对服务异常处理
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = TxnException.class)
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnExceptionHandler(TxnException e) {
		logger.error(EXCEPTION_HANDLER,e);
		return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
	}

	/**
	 * 对拒绝异常处理
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = TxnForbiddenException.class)
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnForbiddenExceptionHandler(TxnForbiddenException e) {
		logger.error(EXCEPTION_HANDLER,e);
		return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
	}

	/**
	 * 对未授权异常处理
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = TxnUnauthorizedException.class)
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnUnauthorizedExceptionHandler(TxnUnauthorizedException e) {
		logger.error(EXCEPTION_HANDLER,e);
		return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
	}

	/**
	 * 对未发现异常处理
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = TxnNotFoundException.class)
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnNotFoundExceptionHandler(TxnNotFoundException e) {
		logger.error(EXCEPTION_HANDLER,e);
		return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
	}

	/**
	 * 对错误的请求处理 包括参数检查错误
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value = {TxnArgumentException.class, MethodArgumentNotValidException.class})
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnArgumentExceptionHandler(Exception e) {
		if (e instanceof TxnArgumentException) {
			TxnArgumentException ex = (TxnArgumentException) e;
			logger.error("TxnArgumentException:",e);
			return new TxnRespResult<>().getFail(ex.getErrCode(), ex.getErrMsg());
		} else if (e instanceof MethodArgumentNotValidException) {
			logger.error("MethodArgumentNotValidException:",e);
			return methodArgumentNotValidExceptionHandler((MethodArgumentNotValidException) e);
		} else {
			logger.error(EXCEPTION_HANDLER,e);
			return new TxnRespResult<>().getFail(TxnRespCode.PARAM_ERROR.getCode(), "参数检查错误");
		}
	}

	private TxnRespResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {
		TxnRespResult result = new TxnRespResult();
		// 参数校验异常
		List<ObjectError> errors = ex.getBindingResult().getAllErrors();
		if (!errors.isEmpty()) {
			// 获取所有出错字段及错误信息，FieldName -> ErrorMessage (字段名称 -> 对应的错误信息)
			StringBuilder errorFieldMsg = new StringBuilder();
			for (ObjectError error : errors) {
				if (error instanceof FieldError) {
					FieldError fieldError = (FieldError) error;
					errorFieldMsg.append(fieldError.getDefaultMessage()).append(";");

					logger.info("参数校验失败, field={}, errorMsg={}, fieldValue={}",
							fieldError.getField(), fieldError.getDefaultMessage(), fieldError.getRejectedValue());
				}
			}
			// 将校验失败的字段的错误信息放到result的message中
			result.getFail(TxnRespCode.PARAM_ERROR.getCode(), errorFieldMsg.toString());
		} else {
			result.getFail(TxnRespCode.PARAM_ERROR.getCode(), "参数检查错误");
		}
		return result;
	}

	@ExceptionHandler(value = {TxnBeanMappingException.class})
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult txnBeanMappingExceptionHandler(TxnBeanMappingException e) {
		logger.error(EXCEPTION_HANDLER,e);
		return new TxnRespResult<>().getFail(e.getErrCode(), e.getErrMsg());
	}

	/**
	 * 参数类型转换错误
	 *
	 * @param exception 错误
	 * @return 错误信息
	 */
	@ExceptionHandler(HttpMessageConversionException.class)
	@ResponseBody
	@ResponseStatus(HttpStatus.OK)
	public TxnRespResult parameterTypeException(HttpMessageConversionException exception) {

		logger.error("HttpMessageConversionException:",exception);
		String soap = exception.getCause().getLocalizedMessage();

		String reportMsg="Unexpected character";
		if (soap.contains(reportMsg)){
			return  new TxnRespResult().getFail(TxnRespCode.PARAM_ERROR.getCode(),"请求中报文中含有非法字符");
		}
		// 匹配的模式
		Matcher matcher = pattern.matcher(soap);
		String param = "";
		int i = 0;
		String listParam = "";
		String listIndex = "";
		while (matcher.find(i)) {
			String term = matcher.group(1);
			if (term.contains("List")) {
				listParam = term;
			}
			if (StringUtils.isNumber(term)) {
				listIndex = term;
			}
			param = term;
			i = matcher.end() + 1;
		}
		if (!"".equalsIgnoreCase(listParam)) {
			return new TxnRespResult().getFail(TxnRespCode.PARAM_ERROR.getCode(), "集合[" + listParam + "]的下标为[" + listIndex + "]的对象的属性[" + param + "]的参数不正确，导致类型转换错误");
		}
		return new TxnRespResult().getFail(TxnRespCode.PARAM_ERROR.getCode(), "请求中的" + param + "参数不正确，导致类型转换错误");

	}
}